package com.llyb.aspect;

import com.llyb.annotation.MyCacheAnnotation;
import com.llyb.entities.User;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

@Component
@Aspect
@Slf4j
public class CacheAspect {

    @Autowired
    private RedisTemplate redisTemplate;

    @Pointcut("@annotation(com.llyb.annotation.MyCacheAnnotation)")
    public void cachePointCut(){}

    @Around("cachePointCut()")
    public Object doCache(ProceedingJoinPoint joinPoint){
        User user = null;

        // 1.取出形参
        Object[] args = joinPoint.getArgs();

        // 2.取出方法名 和上面的注解
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        MyCacheAnnotation annotation = method.getAnnotation(MyCacheAnnotation.class);

        // 3.拿出注解的参数
        String keyPrefix = annotation.keyPrefix();
        String matchMessage = annotation.matchMessage();

        // 4.spl 解析器
        SpelExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression(matchMessage);
        StandardEvaluationContext context = new StandardEvaluationContext();


        // 5.用splex表达式替换
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < args.length; i++) {
            System.out.println("将名为"+parameters[i].getName() +"替换为"+args[i].toString());
            context.setVariable(parameters[i].getName(),args[i].toString());
        }


        // 6.去redis查询有没有，有直接返回
        String key = keyPrefix + ":" + expression.getValue(context).toString();
        user = (User) redisTemplate.opsForValue().get(key);
        if (!ObjectUtils.isEmpty(user)) {
            return user;
        }

        // 7.执行方法
        try {
            user = (User) joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }


        // 8.缓存补偿到redis中
        if (!ObjectUtils.isEmpty(user)) {
            redisTemplate.opsForValue().set(key,user);
        }

        return user;
    }

}
